package plggnssclib

// #cgo !windows LDFLAGS: -lm -lrt -lpthread
//#include "appmain.h"
//#include "skyex.h"
import "C"

import (
	"dgo/MyProj/PrjHttpUtils"
	"dgo/goutils/gis"
	"dgo/goutils/gnss"
	"dgo/goutils/utils"
	"gitee.com/ymofen/supervalue"

	"fmt"
	"net/http"
	"strings"
	"time"
	"unsafe"
)

type SkyPlotRequest struct {
	removeflag int32

	info    string
	uuid    string
	reqt    time.Time
	x, y, z float64

	resprawtext string
	respt       time.Time
	respcnt     int

	resp_final_latest   string
	resp_final_latest_t time.Time

	respfn func(req *SkyPlotRequest)
}

func (this *SkyPlotRequest) doResp(v string) {
	this.resprawtext = v
	this.respt = time.Now()
	this.respcnt++
	if this.respfn != nil {
		this.respfn(this)
	}
}

func NewSkyPlotRequest() *SkyPlotRequest {
	rval := &SkyPlotRequest{}
	rval.uuid = utils.RandKeyString(24)
	return rval
}

type PlgGnssSkyPlotController struct {
	task_n int32
	PlgBase
	lastResp           string
	skyex_eph_channel  string
	skyex_req_channel  string
	skyex_resp_channel string
	inputEph           *PlgBaseInnerEx
	reqlst             utils.GSyncMapGroup
	warnlst            *utils.SyncCycleList
}

/*
*

	{
	  "id": "skyplot",
	  "type": "gnss.clib.sky",
	  "conf": {
	    "input-eph":{
	        "id":"xxx",
	        "topic":""
	     }
	  }
	}
*/
func (this *PlgGnssSkyPlotController) ReloadConf(conf *wrapper.SuperValue) error {

	if this.warnlst == nil {
		this.warnlst = utils.NewSyncCycleList()
		this.warnlst.ConfigMaxSize(1024)
	}

	if this.inputEph == nil {
		this.inputEph = PlgNewInnerEx()
		C.Init()
	}

	this.inputEph.ReloadConfAndSubscribe(conf.ValueByName("input-eph"), func(sender interface{}, channelid string, subscribeid interface{}, data interface{}, tag interface{}, isBreak *bool) bool {
		if buf, ok := data.([]byte); ok {
			utils.DefaultWorkers().PostTaskFunc(this, func() {
				ci := C.int(len(buf))
				c_buf := (*C.char)(unsafe.Pointer(&buf[0]))
				C.skyex_inputbuf(C.obj, c_buf, ci)
			})
		}
		return true
	})

	return nil
}

func (this *PlgGnssSkyPlotController) RequestSKyPlot(x, y, z float64, t time.Time, satids string, showAll bool) string {
	var stax = [3]float64{x, y, z}

	if t.IsZero() {
		t = time.Now()
	}
	mjd, sod := gnss.Time2MJD(t)

	var outbuf [4096]byte
	c_char := (*C.char)(unsafe.Pointer(&outbuf[0]))
	c_stax := (*C.double)(unsafe.Pointer(&stax[0]))
	Cmjd := C.int(mjd)
	Csod := C.double(float64(sod))

	var p C.int
	p = C.skyex_calcu(C.obj, c_stax, c_char, Cmjd, Csod)
	str := string(outbuf[:p])
	str = utils.ReplaceMultiSpace2One(str, " ")
	if showAll {
		outlst := strings.Split(str, "\n")
		str = ""
		bd_cnt := 0
		for _, s := range outlst {
			s1 := utils.Trim(s)
			//卫星号 高度角 方位角
			//G03 29.86 -79.06
			lst := strings.SplitN(s1, " ", 2)
			if len(lst) < 2 {
				continue
			}

			_s1, _ := utils.Split2Str(lst[1], " ")
			if utils.StrToFloat64Def(_s1, 0) < 0 {
				continue
			}

			if strings.Contains(satids, lst[0]) {
				str += utils.Trim(s1) + " 1\n"
				if s1[0] == 'C' {
					bd_cnt++
				}
			} else {
				str += utils.Trim(s1) + " 0\n"
			}
		}
	} else if len(satids) > 0 {
		outlst := strings.Split(str, "\n")
		str = ""
		for _, s := range outlst {
			s1 := utils.Trim(s)
			lst := strings.SplitN(s1, " ", 2)
			if len(lst) < 2 {
				continue
			}
			if strings.Contains(satids, lst[0]) {
				str += utils.Trim(s1) + "\n"
			}
		}
	}

	return str
}

/*
*
url:http://127.0.0.1:15100/plug/do?id=skyplot&all=1&lng=111.11&lat=111.2&h=0&satids=G01,G02&timestamp=12211&resp=txt
url:http://58.49.94.210:15101/plug/do?id=skyplot&all=1&lng=114.465884&lat=30.422786&h=0&satids=C01,G01,G02&timestampXX=12211&resp=txt
*/
func (this *PlgGnssSkyPlotController) OnHttpDo(rec *PlgHttpRec) (rval interface{}, errcode int, err error) {

	showAll := rec.QryAsBool("all", false)
	resptypestr := rec.QryAsString("resp", "txt")

	utcT := time.Now().UTC()
	str := rec.QryAsString("time", "")
	if len(str) > 0 {
		utcT = utils.TryStrToTime(str, time.UTC, time.Now().UTC())
	} else {
		v1 := rec.QryAsInt64("timestamp", 0)
		if v1 > 0 {
			utcT = time.Unix(v1, 0)
		}
	}

	lng := rec.QryAsFloat64("lng", 0)
	lat := rec.QryAsFloat64("lat", 0)
	h := rec.QryAsFloat64("h", 0)
	var x, y, z float64

	satids := rec.QryAsString("satids", "")
	if lng == 0 || lat == 0 {
		x = rec.QryAsFloat64("x", 0)
		y = rec.QryAsFloat64("y", 0)
		z = rec.QryAsFloat64("z", 0)
	} else {
		x, y, z = gis.PosiLatLngH2EcefXyz(lat, lng, h)
	}

	if x == 0 || y == 0 {
		rec.ResponseJSONValues("code", -1, "errcode", ERR_IN_PARAM_INVALID, "msg", "未指定位置")
		return
	}

	wt := utils.NewWaitWithTimeoutAdd1()
	utils.DefaultWorkers().PostTaskFunc(this, func() {
		str := this.RequestSKyPlot(x, y, z, utcT, satids, showAll)
		if resptypestr == "txt" {
			rec.ResponseText(str)
		} else {
			rec.ResponseJSONValues("code", 0, "data", str)
		}
		wt.Done()
	})
	r := wt.WaitFor(time.Second * 30)
	if !r {
		if resptypestr == "txt" {
			http.Error(rec.RespW, "wait timeout!", 503)
			//rec.ResponseText("wait timeout!")
		} else {
			http.Error(rec.RespW, utils.BuildJSONString("code", -1, "msg", "wait timeout!!!"), 503)
		}
	}

	return
}

func (this *PlgGnssSkyPlotController) OnHttpStatus(rec *PlgHttpRec) (rval interface{}, errcode int, err error) {
	itype := rec.QryAsInt("type", 0)
	if itype == 1 {
		json := wrapper.NewSVArray()
		waitflag := rec.QryAsInt("waitflag", 0)
		searchval := rec.QryAsString("searchval", "")
		this.reqlst.ListRangeV2(func(key, value interface{}) bool {
			val := value.(*SkyPlotRequest)
			ret := true
			if waitflag == 1 && ret {
				ret = ret && val.respcnt == 0
			}
			if len(searchval) > 0 && ret {
				ret = (strings.Contains(val.info, searchval)) || strings.Contains(val.uuid, searchval)
				if !ret {
					xyz := fmt.Sprintf("%.6f %.6f %.4f", val.x, val.y, val.z)
					ret = ret || strings.Contains(xyz, searchval)
				}
			}

			return ret
		}, func(k0, v0, k1, v1 interface{}) bool {
			req0 := v0.(*SkyPlotRequest)
			req1 := v1.(*SkyPlotRequest)
			return req0.reqt.Before(req1.reqt)
		}, func(key, val interface{}) bool {
			req := val.(*SkyPlotRequest)
			itm := json.AppendObject()
			itm.SetKeyValue("uuid", req.uuid)
			itm.SetKeyValue("reqt", utils.DateTimeStringForShortShow(req.reqt))
			itm.SetKeyValues("info", req.info)
			itm.SetKeyValues("xyz", fmt.Sprintf("%.6f %.6f %.4f", req.x, req.y, req.z))
			if req.respt.IsZero() {
				itm.SetKeyValues("consume", fmt.Sprintf("%d(ms)", time.Since(req.reqt).Milliseconds()))
			} else {
				itm.SetKeyValues("consume", fmt.Sprintf("%d(ms)", req.respt.Sub(req.reqt).Milliseconds()))
			}
			itm.SetKeyValues("resptext", fmt.Sprintf("[%d][%s]%s", req.respcnt, utils.DateTimeStringForShortShow(req.respt), req.resp_final_latest))
			return true
		})
		PrjHttpUtils.JSON2TableEx(rec.RespW, "", json.AsJSONString(false), nil)
	} else if itype == 2 {
		rec.ResponseSyncListNEx(this.warnlst)
	} else if itype == 3 {
		rec.ResponseText(this.lastResp)
	} else if itype == 99 {
		json := wrapper.NewSVObject()
		json.SetKeyValues("task-n", this.task_n)

		json.SetKeyValue("now", utils.NowString())
		PrjHttpUtils.JSON2TableRec(rec.RespW, "", json.AsJSONString(false))
	} else {
		var sb utils.BytesBuilder
		PrjHttpUtils.AppendIndexBody(&sb, "status", "status?type=99")
		PrjHttpUtils.AppendIndexBody(&sb, "list", "status?type=1&waitflag=1&searchval=")
		PrjHttpUtils.AppendIndexBody(&sb, "warnlst", "status?type=2&searchval=&n=100")
		PrjHttpUtils.AppendIndexBody(&sb, "lastrespfromalg", "status?type=3")
		PrjHttpUtils.AppendIndexBody(&sb, "test", "do?all=1&lng=114.465884&lat=30.422786&h=0&satids=C01,G01,G02&timestampXX=12211&resptext=txt")
		PrjHttpUtils.ResponseBodyHtml(rec.RespW, sb.String())
	}

	return
}

func CreatePlgGnssSkyPlotControllerFunc(args ...interface{}) (rval interface{}, err error) {
	obj := &PlgGnssSkyPlotController{}
	if len(args) > 0 {
		if str, ok := args[0].(string); ok {
			obj.PlugId = str
		}
	}
	rval = obj
	return
}
